package eval.host;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import eval.utilities.configuration.ExperimentConfiguration;
import eval.utilities.random.RandomUtilities;

/**
 * This class is responsible for creating a new host in the cloud.
 * It can creates the hosts population exactly as defined in the input 
 * configuration file (e.g constant distribution),(recommended),
 * Or, it can creates a random hosts population, base on the probability of
 * each host type (e.g random distribution).
 *  
 * @author Amit Peled   <amit.kapina@gmail.com>
 * @author Igal Kaufman <igal.kaufman@gmail.com> 
 */
public class HostGenerator {

	protected ExperimentConfiguration configuration = ExperimentConfiguration.getSingleton();
	private IHostManager hostManager;


	/**
	 * @Constructor
	 * @param hostManager
	 */
	public HostGenerator(IHostManager hostManager) {
		this.hostManager = hostManager;
	}

	/**
	 * Generate Hosts
	 * 
	 * @param totalNumberOfHosts the number of hosts to generate
	 * @return list of new Hosts
	 */
	public List<Host> generateHosts(int totalNumberOfHosts) {
		if(configuration.hostsTypesDistribution.equals("RANDOM")){
			List<Host> hostList = new ArrayList<Host>();
			for (int i = 0; i < totalNumberOfHosts; i++)
				hostList.add(generateNewHostRandomly());
			return hostList;
		} else if(configuration.hostsTypesDistribution.equals("CONSTANT")){
			return generateNewHostConstantly(totalNumberOfHosts);
		} else
			throw new IllegalArgumentException("Error while generating hosts, no such distribution: " + configuration.hostsTypesDistribution +".");
	}

	/**
	 * Generate single Host (by random)
	 * 
	 * @return the new Host
	 */
	public Host generateNewHostRandomly() {
		RandomUtilities tmp = new RandomUtilities();
		double randomNumber = tmp.generateNewRandomNumber();
		Map<HostCapacityEnum, Double> hostDistribution = hostManager
				.getHostDistribution();

		double sum = 0;
		for (HostCapacityEnum value : HostCapacityEnum.values()) {
			sum += hostDistribution.get(value);
			if (randomNumber <= sum)
				return new Host(value,hostManager.getHostCapacity(value),configuration.hostCounter++);
		}
		throw new IllegalArgumentException("Error while generating a new host");
	}

	/**
	 * Generate Hosts (the hosts distribution will be constant)
	 * 
	 * @param totalNumberOfHosts the number of hosts to generate
	 * @return list of new Hosts
	 */
	public List<Host> generateNewHostConstantly(int totalNumberOfHosts){
		List<Host> hostList = new ArrayList<Host>();
		Map<HostCapacityEnum, Double> hostDistribution = hostManager
				.getHostDistribution();

		for (HostCapacityEnum value : HostCapacityEnum.values()) {
			double typePercenetage = hostDistribution.get(value);
			double numOfHostPerType = totalNumberOfHosts * typePercenetage;

			if(numOfHostPerType == Math.round(numOfHostPerType)){
				for(int i=0 ; i < totalNumberOfHosts * typePercenetage ; i++){
					hostList.add(new Host(value,hostManager.getHostCapacity(value),configuration.hostCounter++));
				}
			}
			else{throw new IllegalArgumentException("the Number of Hosts per type must be a round number.");}
		}

		return hostList;
	}



}
